package com.spica.spicaschool.ui.sportMap


import android.animation.Animator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.graphics.Color
import android.os.*
import android.view.KeyEvent
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.location.AMapLocationClient
import com.amap.api.location.AMapLocationClientOption
import com.amap.api.location.AMapLocationListener
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapUtils
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.LocationSource
import com.amap.api.maps.LocationSource.OnLocationChangedListener
import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.LatLngBounds
import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.kongzue.dialogx.dialogs.MessageDialog
import com.kongzue.dialogx.dialogs.TipDialog
import com.kongzue.dialogx.dialogs.WaitDialog
import com.skydoves.whatif.whatIfNotNull
import com.spica.spicaschool.AppHolder
import com.spica.spicaschool.R
import com.spica.spicaschool.bean.PathRecord
import com.spica.spicaschool.bean.SportMotionRecord
import com.spica.spicaschool.databinding.ActivitySportMapBinding
import com.spica.spicaschool.persistence.dao.SportMotionRecordDao
import com.spica.spicaschool.service.PathSmoothTool
import com.spica.spicaschool.service.amapLocationToString
import com.spica.spicaschool.service.calculationCalorie
import com.spica.spicaschool.service.getLatLngPathLineString
import com.spica.spicaschool.utils.CountTimerUtil
import com.spica.spicaschool.utils.CountTimerUtil.AnimationState
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import timber.log.Timber
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
import javax.inject.Inject


/**
 *  运动地图轨迹绘制
 */
private const val interval: Long = 2000L //定位时间间隔

@AndroidEntryPoint
class SportMapActivity : AppCompatActivity(), AMapLocationListener {


  @Inject
  lateinit var recordDao: SportMotionRecordDao

  private lateinit var viewBinding: ActivitySportMapBinding

  private var isStartUp = false

  private var seconds: Long = 0 //秒数(时间)

  private var mStartTime: Long = 0 //开始时间
  private var mEndTime: Long = 0 //结束时间
  private var distance = 0.0 //路程

  private var mode = true //模式 true&false：是否显示地图

  private var record: PathRecord? = null // 应该用来存储轨迹信息的对象

  private val mHandler = Handler(Looper.getMainLooper()) //主线程Handler

  private var mLocationClient: AMapLocationClient? = null

  private lateinit var polylineOptions: PolylineOptions


  private var aMap: AMap? = null

  private var runtime = MyRunnable()

  private var mSportLatLngs: MutableList<LatLng> = ArrayList(0)

  private lateinit var apperaAnim1: ValueAnimator
  private lateinit var hiddenAnim1: ValueAnimator

  private lateinit var apperaAnim2: ValueAnimator
  private lateinit var hiddenAnim2: ValueAnimator

  private lateinit var apperaAnim3: ValueAnimator
  private lateinit var hiddenAnim3: ValueAnimator

  private lateinit var mpathSmoothTool: PathSmoothTool

  //位置信息更换的监听器
  private var mListener: OnLocationChangedListener? = null

  //运动计算相关（数字格式化）
  private val decimalFormat = DecimalFormat("0.00")

  private var mLocationOption: AMapLocationClientOption? = null

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    viewBinding = ActivitySportMapBinding.inflate(layoutInflater)
    setContentView(viewBinding.root)
    viewBinding.mapView.onCreate(savedInstanceState)
    initData()
    initClickListener()
  }


  private fun formatseconds(): String {
    val hh = if (seconds / 3600 > 9) (seconds / 3600).toString() + "" else "0${seconds / 3600}"
    val mm =
      if (seconds % 3600 / 60 > 9) (seconds % 3600 / 60).toString() + "" else "0${seconds % 3600 / 60}"
    val ss =
      if (seconds % 3600 % 60 > 9) (seconds % 3600 % 60).toString() + "" else "0${seconds % 3600 % 60}"
    seconds++
    return "$hh:$mm:$ss"
  }


  //计时+1S
  private inner class MyRunnable : Runnable {
    override fun run() {
      viewBinding.cmPasstime.text = formatseconds()
      mHandler.postDelayed(this, 1000)
    }
  }

  private fun getBounds(pointlist: List<LatLng>?): LatLngBounds? {
    val b = LatLngBounds.builder()
    if (pointlist == null) {
      return b.build()
    }
    for (latLng in pointlist) {
      b.include(latLng)
    }
    return b.build()
  }


  override fun onResume() {
    super.onResume()
    viewBinding.mapView.onResume()
  }


  override fun onPause() {
    viewBinding.mapView.onPause()
    super.onPause()
  }


  private fun initMap() {
    aMap?.setLocationSource(locationSource)
    // 自定义系统定位小蓝点
    val myLocationStyle = MyLocationStyle()
    myLocationStyle.strokeColor(Color.TRANSPARENT)
    myLocationStyle.radiusFillColor(Color.argb(0, 0, 0, 0))// 设置圆形的填充颜色
    myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
    myLocationStyle.strokeWidth(1.0f)
    aMap?.myLocationStyle = myLocationStyle
    aMap?.uiSettings?.isMyLocationButtonEnabled = true// 设置默认定位按钮是否显示
    aMap?.uiSettings?.isZoomControlsEnabled = false// 设置默认缩放按钮是否显示
    aMap?.uiSettings?.isCompassEnabled = false// 设置默认指南针是否显示
    aMap?.isMyLocationEnabled = true// 设置为true表示显示定位层并可触发定位，false表示隐藏定位层并不可触发定位，默认是false
  }


  private val locationSource: LocationSource = object : LocationSource {
    override fun activate(onLocationChangedListener: OnLocationChangedListener) {
      mListener = onLocationChangedListener
      startLocation()
    }

    override fun deactivate() {
      mListener = null
      mLocationClient.whatIfNotNull {
        it.stopLocation()
        it.onDestroy()
      }
      mLocationClient = null
    }
  }


  override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) {
    super.onSaveInstanceState(outState, outPersistentState)
    viewBinding.mapView.onSaveInstanceState(outState)
  }

  private fun initData() {
    //显示倒计时
    CountTimerUtil.start(viewBinding.tvNumberAnim, object : AnimationState {
      override fun start() {}
      override fun repeat() {}
      override fun end() {
        viewBinding.tvNumberAnim.visibility = View.GONE
        hiddenAnim1.start()
        hiddenAnim3.start()
        isStartUp = true
        seconds = 0
        viewBinding.cmPasstime.base = SystemClock.elapsedRealtime()
        mStartTime = System.currentTimeMillis()
        if (record == null) record = PathRecord()
        record?.mStartTime = (mStartTime)
        mHandler.postDelayed(runtime, 0)
        startUpLocation()
      }
    })
    if (aMap == null) {
      aMap = viewBinding.mapView.map
    }
    initMap()
    initPolyline()
    setMode()
  }

  private fun initPolyline() {
    polylineOptions = PolylineOptions()
    polylineOptions.color(getColor(R.color.colorAccent))
    polylineOptions.width(20f)
    polylineOptions.useGradient(true)
    mpathSmoothTool = PathSmoothTool()
    mpathSmoothTool.intensity = 4
  }

  private fun setMode() {
    if (mode) {
      viewBinding.tvMode.text = "地图模式"
      viewBinding.mapView.visibility = View.GONE
    } else {
      viewBinding.tvMode.text = "跑步模式"
      viewBinding.mapView.visibility = View.VISIBLE
    }
    mode = !mode
  }

  private fun startUpLocation() {
    viewBinding.root.keepScreenOn = true
    startLocation()
  }


  override fun onWindowFocusChanged(hasFocus: Boolean) {
    if (hasFocus) {
      setApperaAnimationView()
      setHiddenAnimationView()
    }
    super.onWindowFocusChanged(hasFocus)
  }


  /**
   * 创建动画
   */
  private fun setHiddenAnimationView() {
    hiddenAnim1 = ValueAnimator.ofFloat(0f, (viewBinding.tvFinish.height * 2).toFloat())
    hiddenAnim1.duration = 500
    hiddenAnim1.setTarget(viewBinding.tvFinish)
    hiddenAnim1.addUpdateListener { animation: ValueAnimator ->
      viewBinding.tvFinish.translationY = animation.animatedValue as Float
    }
    hiddenAnim1.addListener(object : Animator.AnimatorListener {
      override fun onAnimationStart(animation: Animator) {
        viewBinding.tvFinish.isEnabled = false
      }

      override fun onAnimationEnd(animation: Animator) {
        viewBinding.tvFinish.isEnabled = true
      }

      override fun onAnimationCancel(animation: Animator) {
        viewBinding.tvFinish.isEnabled = true
      }

      override fun onAnimationRepeat(animation: Animator) {}
    })
    hiddenAnim2 = ValueAnimator.ofFloat(0f, (viewBinding.tvSuspend.height * 2).toFloat())
    hiddenAnim2.duration = 500
    hiddenAnim2.setTarget(viewBinding.tvSuspend)
    hiddenAnim2.addUpdateListener { animation: ValueAnimator ->
      viewBinding.tvSuspend.translationY = animation.animatedValue as Float
    }
    hiddenAnim2.addListener(object : Animator.AnimatorListener {
      override fun onAnimationStart(animation: Animator) {
        viewBinding.tvSuspend.isEnabled = false
      }

      override fun onAnimationEnd(animation: Animator) {
        viewBinding.tvSuspend.isEnabled = true
      }

      override fun onAnimationCancel(animation: Animator) {
        viewBinding.tvSuspend.isEnabled = true
      }

      override fun onAnimationRepeat(animation: Animator) {}
    })
    hiddenAnim3 = ValueAnimator.ofFloat(0f, (viewBinding.tvContinue.height * 2).toFloat())
    hiddenAnim3.duration = 500
    hiddenAnim3.setTarget(viewBinding.tvContinue)
    hiddenAnim3.addUpdateListener { animation: ValueAnimator ->
      viewBinding.tvContinue.translationY = animation.animatedValue as Float
    }
    hiddenAnim3.addListener(object : Animator.AnimatorListener {
      override fun onAnimationStart(animation: Animator) {
        viewBinding.tvContinue.isEnabled = false
      }

      override fun onAnimationEnd(animation: Animator) {
        viewBinding.tvContinue.isEnabled = true
      }

      override fun onAnimationCancel(animation: Animator) {
        viewBinding.tvContinue.isEnabled = true
      }

      override fun onAnimationRepeat(animation: Animator) {}
    })
  }

  /**
   * 创建动画
   */
  private fun setApperaAnimationView() {
    apperaAnim1 = ValueAnimator.ofFloat((viewBinding.tvFinish.height * 2).toFloat(), 0f)
    apperaAnim1.duration = 500
    apperaAnim1.setTarget(viewBinding.tvFinish)
    apperaAnim1.addUpdateListener { animation: ValueAnimator ->
      viewBinding.tvFinish.translationY = animation.animatedValue as Float
    }
    apperaAnim1.addListener(object : Animator.AnimatorListener {
      override fun onAnimationStart(animation: Animator) {
        viewBinding.tvFinish.isEnabled = false
      }

      override fun onAnimationEnd(animation: Animator) {
        viewBinding.tvFinish.isEnabled = true
      }

      override fun onAnimationCancel(animation: Animator) {
        viewBinding.tvFinish.isEnabled = true
      }

      override fun onAnimationRepeat(animation: Animator) {}
    })
    apperaAnim2 = ValueAnimator.ofFloat((viewBinding.tvSuspend.height * 2).toFloat(), 0f)
    apperaAnim2.duration = 500
    apperaAnim2.setTarget(viewBinding.tvSuspend)
    apperaAnim2.addUpdateListener { animation: ValueAnimator ->
      viewBinding.tvSuspend.translationY = animation.animatedValue as Float
    }
    apperaAnim2.addListener(object : Animator.AnimatorListener {
      override fun onAnimationStart(animation: Animator) {
        viewBinding.tvSuspend.isEnabled = false
      }

      override fun onAnimationEnd(animation: Animator) {
        viewBinding.tvSuspend.isEnabled = true
      }

      override fun onAnimationCancel(animation: Animator) {
        viewBinding.tvSuspend.isEnabled = true
      }

      override fun onAnimationRepeat(animation: Animator) {}
    })
    apperaAnim3 = ValueAnimator.ofFloat((viewBinding.tvContinue.height * 2).toFloat(), 0f)
    apperaAnim3.duration = 500
    apperaAnim3.setTarget(viewBinding.tvContinue)
    apperaAnim3.addUpdateListener { animation: ValueAnimator ->
      viewBinding.tvContinue.translationY = animation.animatedValue as Float
    }
    apperaAnim3.addListener(object : Animator.AnimatorListener {
      override fun onAnimationStart(animation: Animator) {
        viewBinding.tvContinue.isEnabled = false
      }

      override fun onAnimationEnd(animation: Animator) {
        viewBinding.tvContinue.isEnabled = true
      }

      override fun onAnimationCancel(animation: Animator) {
        viewBinding.tvContinue.isEnabled = true
      }

      override fun onAnimationRepeat(animation: Animator) {}
    })
  }


  /**
   * 开始定位。
   */
  private fun startLocation() {
    if (mLocationClient == null) {
      mLocationClient = AMapLocationClient(this)
      //设置定位属性
      mLocationOption = AMapLocationClientOption()
      mLocationOption?.locationMode =
        AMapLocationClientOption.AMapLocationMode.Hight_Accuracy //可选，设置定位模式，可选的模式有高精度、仅设备、仅网络。默认为高精度模式
      mLocationOption?.isGpsFirst = false //可选，设置是否gps优先，只在高精度模式下有效。默认关闭
      mLocationOption?.httpTimeOut = 30000 //可选，设置网络请求超时时间。默认为30秒。在仅设备模式下无效
      mLocationOption?.interval = interval //可选，设置定位间隔。默认为2秒
      mLocationOption?.isNeedAddress = false //可选，设置是否返回逆地理地址信息。默认是true
      mLocationOption?.isOnceLocation = false //可选，设置是否单次定位。默认是false
      mLocationOption?.isOnceLocationLatest =
        false //可选，设置是否等待wifi刷新，默认为false.如果设置为true,会自动变为单次定位，持续定位时不要使用
      AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTPS) //可选， 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
      mLocationOption?.isSensorEnable = false //可选，设置是否使用传感器。默认是false
      mLocationOption?.isWifiScan =
        true //可选，设置是否开启wifi扫描。默认为true，如果设置为false会同时停止主动刷新，停止以后完全依赖于系统刷新，定位位置可能存在误差
      mLocationOption?.isLocationCacheEnable = true //可选，设置是否使用缓存定位，默认为true
      mLocationOption?.geoLanguage =
        AMapLocationClientOption.GeoLanguage.ZH //可选，设置逆地理信息的语言，默认值为默认语言（根据所在地区选择语言）
      mLocationClient?.setLocationOption(mLocationOption)
      // 设置定位监听
      mLocationClient?.setLocationListener(this)
      //开始定位
      mLocationClient?.startLocation()
    }
  }


  private fun initClickListener() {

    viewBinding.tvMode.setOnClickListener {
      setMode()
    }

    viewBinding.tvFinish.setOnClickListener {
      mHandler.removeCallbacks(runtime)
      isStartUp = true
      hiddenAnim1.start()
      hiddenAnim3.start()
      //保存数据
      if (null != record && !record?.mPathLinePoints.isNullOrEmpty()) {
        saveRecord()
      } else {
        TipDialog.show("没有记录到路径!")
        finish()
      }
    }
    viewBinding.tvSuspend.setOnClickListener {
      isStartUp = false
      mEndTime = System.currentTimeMillis()
      mHandler.removeCallbacks(runtime)
      aMap?.moveCamera(CameraUpdateFactory.newLatLngBounds(getBounds(mSportLatLngs), 20))
      apperaAnim1.start()
      hiddenAnim2.start()
      apperaAnim3.start()
    }
    viewBinding.tvContinue.setOnClickListener {
      isStartUp = true
      mHandler.postDelayed(runtime, 0)
      startUpLocation()
      hiddenAnim1.start()
      apperaAnim2.start()
      hiddenAnim3.start()
    }
  }


  /**
   * 保存数据
   */
  private fun saveRecord() {
    WaitDialog.show("正在保存运动数据")
    try {

      val locations: MutableList<LatLng> = mutableListOf()
      record.whatIfNotNull {
        locations.addAll(it.mPathLinePoints)
      }
      val firstLocaiton = locations[0]
      val lastLocaiton = locations[locations.size - 1]
      val sportMile = distance / 1000.0

      val userId = AppHolder.user?.id?.toLong() ?: 1L

      val sportMotionRecord = SportMotionRecord(
        distance = distance,
        duration = seconds,
        userId = userId,
        mStartTime = mStartTime,
        mEndTime = mEndTime,
        stratPoint = amapLocationToString(firstLocaiton),
        endPoint = amapLocationToString(lastLocaiton),
        pathLine = getLatLngPathLineString(locations),
        calorie = calculationCalorie(60.0, sportMile),
        speed = sportMile / (seconds.toDouble() / 3600),
        distribution = record?.mDistribution,
        dateTag = getStringDateShort(mEndTime)
      )

      Timber.e("保存用户数据:${sportMotionRecord}")
      //保存用户数据
      lifecycleScope.launch(Dispatchers.IO) {
        recordDao.insert(sportMotionRecord)
      }
    } catch (e: Exception) {
      Timber.e("保存运动数据失败$e")
    }
    mHandler.postDelayed({
      WaitDialog.dismiss()
      setResult(RESULT_OK)
      finish()
    }, 1500)
  }


  //计算距离
  private fun getDistance(list: List<LatLng>?): Float {
    var distance = 0f
    if (list == null || list.isEmpty()) {
      return distance
    }
    for (i in 0 until list.size - 1) {
      val firstLatLng = list[i]
      val secondLatLng = list[i + 1]
      val betweenDis = AMapUtils.calculateLineDistance(
        firstLatLng,
        secondLatLng
      ).toDouble()
      distance = (distance + betweenDis).toFloat()
    }
    return distance
  }

  override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    return super.onKeyDown(keyCode, event)
  }


  override fun onBackPressed() {
    //拦截返回
    if (isStartUp) {
      TipDialog.show("请点击暂停，再关闭此页面")
      return
    }

    record.whatIfNotNull {
      if (it.mPathLinePoints.isNotEmpty()) {
        MessageDialog.build()
          .setTitle("提示")
          .setMessage("退出将删除本次运动记录,如要保留运动数据,请点击完成!")
          .setOkButton("确定")
          .show()
      }

    }

    super.onBackPressed()
  }

  override fun onDestroy() {
    super.onDestroy()
    viewBinding.mapView.onDestroy()
  }


  /**
   * 更新绘制轨迹
   */
  @SuppressLint("SetTextI18n")
  private fun updateLocation(aMapLocation: AMapLocation) {
    Timber.e("更新繪製軌跡")
    record?.mPathLinePoints?.add(LatLng(aMapLocation.latitude, aMapLocation.longitude))
    //计算配速
    distance = getDistance(record?.mPathLinePoints).toDouble()
    val sportMile = distance / 1000.0
    //运动距离大于0.2公里再计算配速
    if (!(seconds <= 0 || sportMile <= 0.2)) {
      val distribution = seconds.toDouble() / 60.0 / sportMile
      record?.mDistribution = (distribution)
      viewBinding.tvSpeed.text = decimalFormat.format(distribution)
      viewBinding.tvMileage.text = decimalFormat.format(sportMile)
    } else {
      record?.mDistribution = (0.0)
      viewBinding.tvSpeed.text = "0.00"
      viewBinding.tvMileage.text = "0.00"
    }
    mSportLatLngs.clear()
    //轨迹平滑优化
    mSportLatLngs.addAll(mpathSmoothTool.pathOptimize(record?.mPathLinePoints))
    if (mSportLatLngs.isNotEmpty()) {
      polylineOptions.add(mSportLatLngs[mSportLatLngs.size - 1])
      mListener?.onLocationChanged(aMapLocation) // 显示系统小蓝点
      //相机位移
      Timber.e("相机移动：lon:${aMapLocation.longitude},lat:${aMapLocation.latitude}")
      aMap?.animateCamera(
        CameraUpdateFactory.newLatLngZoom(
          LatLng(
            aMapLocation.latitude,
            aMapLocation.longitude
          ), 18f
        )
      )
    }
    //轨迹绘制
    aMap?.addPolyline(polylineOptions)
  }

  //位置更换回调
  override fun onLocationChanged(aMapLocation: AMapLocation?) {
    if (aMapLocation == null) return

    if (aMapLocation.errorCode == 0) {
      //先暂时获得经纬度信息，并将其记录在List中
      Timber.d("纬度信息为${aMapLocation.latitude}\n经度信息为${aMapLocation.longitude}")
      //定位成功
      updateLocation(aMapLocation)
    } else {
      val errText = "定位失败,${aMapLocation.errorCode}:${aMapLocation.errorInfo}"
      Timber.e("AmapErr${errText}")
    }
  }


  private fun getStringDateShort(time: Long): String {
    val currentTime = Date(time)
    val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
    return formatter.format(currentTime)
  }
}
